package launch

import (
	"bytes"
	"fmt"
	"iot-base/common/config"
	"iot-base/common/dbconn"
	"iot-base/common/dbobj"
	"iot-base/common/eventtype"

	"iot-base/common/logger"
	"iot-base/common/notify"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"
)

func runInWindows(cmd string) *exec.Cmd {
	fmt.Println("Running windows cmd:" + cmd)
	return exec.Command("cmd", "/c", cmd)
}

func RunCommandWait(cmd string) (string, error) {
	var pCmd *exec.Cmd
	var err error
	if runtime.GOOS == "windows" {
		pCmd = runInWindows(cmd)
	} else {
		pCmd = runInLinux(cmd)
	}
	if pCmd != nil {
		result, errRun := pCmd.Output()
		if result != nil && errRun == nil {
			sresult := strings.Replace(string(result), "\n", "", -1)
			sresult = strings.Replace(sresult, "\r", "", -1)
			sresult = strings.Replace(sresult, " ", "", -1)
			fmt.Println("-------check------", sresult)
			return sresult, nil

		}
		fmt.Println("error", errRun)
		return "", errRun
	}
	return "", err
}

func runInLinux(cmd string) *exec.Cmd {
	fmt.Println("Running Linux cmd:" + cmd)
	return exec.Command("/bin/sh", "-c", cmd)
	//return result
}

//根据进程名判断进程是否运行
func CheckProRunning(serverName string) (bool, error) {
	var a string = `ps -ef | grep -v defunct | awk '/` + serverName + `/ && !/awk/ {print $2} '`

	if runtime.GOOS == "windows" {
		if !strings.Contains(serverName, ".exe") {
			serverName = serverName + ".exe"
		}
		//a = fmt.Sprintf(`tasklist /fi "imagename eq %s" /fo table /nh`, serverName)
		//var pCmd *exec.Cmd
		pid, err := exec.Command("tasklist", "/fi", "imagename eq "+serverName, "/fo", "table", "/nh").Output()
		if pid != nil {
			var line = []byte{13}
			count := bytes.Count(pid, line)
			if count > 1 {
				return true, nil
			}
			return false, nil
		}
		return string(pid) != "", err
	}
	pid, err := RunCommandWait(a)
	if err != nil {
		return false, err
	}
	return pid != "", nil

}

func launchApp(name string) bool {
	isExist, _ := CheckProRunning(name)
	if !isExist {
		if !strings.Contains(name, ".exe") && runtime.GOOS == "windows" {
			name = name + ".exe"
		}
		excPath := dir + "/" + name
		fmt.Println("********run:*******", excPath)
		/*pCmd := run(excPath)
		if pCmd != nil {
			go pCmd.Start()
		}*/
		pCmd := exec.Command(excPath)
		if pCmd == nil {
			return false
		}
		go pCmd.Start()
		time.Sleep(1 * time.Second)
		isExist, _ = CheckProRunning(name)
		fmt.Println("--------------found---------", name, "exist", isExist)
		return isExist
	}
	return isExist

}

//Business 业务表，表中BName为行业应用app的名称
type Business struct {
	BName string `gorm:"primarykey" json:"b_name"`
	Note  string `json:"note"`
}

var dir string

func init() {

}
func alarm(result bool, name string) {

	alarm := eventtype.CreateAlarm(config.SelfOption.ID, "system/launch/"+name, 0, !result, 1)
	notify.RawAlarm(&alarm)

}
func init() {
	file, _ := exec.LookPath(os.Args[0])
	path, _ := filepath.Abs(file)
	dir = filepath.Dir(path)
	dbconn.DBConnection.AutoMigrate(&Business{})
	fmt.Println("********************init-------launch----------")
	go func() {
		LaunchService(alarm)
		ticker := time.NewTicker(1 * time.Minute)
		for range ticker.C {
			LaunchService(alarm)
		}
	}()
}

//OnLaunchCallback 启动服务回调
type OnLaunchCallback func(result bool, name string)

var MAPLaunch sync.Map

//LaunchService 启动服务
func LaunchService(fun OnLaunchCallback) {

	var protocols []string
	//var dm string = "dm"
	fmt.Println("********************init-------launch----thrd------")
	dbconn.DBConnection.Model(&dbobj.Thing{}).
		Where(`(is_proxy = False or is_proxy IS NULL) and protocol_path <> '' and protocol_path IS NOT NULL`).Distinct().
		Pluck("protocol_path", &protocols)

	protocols = append(protocols, "dm")
	//if err == nil {
	var business []Business
	err := dbconn.DBConnection.Find(&business).Error
	if err == nil {
		for _, bi := range business {
			protocols = append(protocols, bi.BName)
		}

	}

	var isEdge = (config.PType == "edge")
	if isEdge {
		MAPLaunch.Store("etm", true)
	} else {
		MAPLaunch.Store("tm", false)
	}
	if len(protocols) > 0 {
		for _, name := range protocols {
			if isEdge {
				if !strings.HasPrefix(name, "e") {
					name = "e" + name
				}
			}

			succ := launchApp(name)
			MAPLaunch.Store(name, succ)
			if fun != nil {
				fun(succ, name)
			}
		}
	}
	SaveChildren()

}

//ForceLaunch 强制启动服务
func ForceLaunch() {
	LaunchService(alarm)

}

//SaveChildren 存储被启动服务
func SaveChildren() {
	//var filenames = make([]string, 0, 8)
	file, _ := exec.LookPath(os.Args[0])
	path, _ := filepath.Abs(file)
	filepath := filepath.Dir(path) + "/services"
	fmt.Println("***************", filepath)
	f, err := os.OpenFile(filepath, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0777)

	if err != nil {
		logger.SLog.Error("write services file error", err)
		return
	}
	fmt.Println("**************insert:******begin**")
	defer f.Close()
	MAPLaunch.Range(func(k, v interface{}) bool {
		f.WriteString(k.(string))
		f.WriteString("\n")
		fmt.Println("**************insert:********", k)
		return true
	})
	fmt.Println("**************insert:******end**")

}
